package com.example.bank.application.impl;

import com.example.bank.application.TransferService;
import com.example.bank.common.Result;
import com.example.bank.domain.entity.Account;
import com.example.bank.domain.service.AccountTransferService;
import com.example.bank.domain.types.AuditMessage;
import com.example.bank.exception.DailyLimitExceededException;
import com.example.bank.exception.InsufficientFundsException;
import com.example.bank.exception.InvalidCurrencyException;
import com.example.bank.external.ExchangeRateService;
import com.example.bank.messaging.AuditMessageProducer;
import com.example.bank.repository.AccountRepository;
import com.example.bank.types.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

@Service
public class TransferServiceImpl implements TransferService {

    @Autowired
    private AccountRepository accountRepository;

    private AuditMessageProducer auditMessageProducer; //没有交给spring容器管理，要自己初始化这个对象才能使用
    private ExchangeRateService exchangeRateService;
    private AccountTransferService accountTransferService;

//    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> transfer(Long sourceUserId, String targetAccountNumber, BigDecimal targetAmount, String targetCurrency) throws Exception, DailyLimitExceededException {
        //根据钱和货币类型创建money
        Money targetMoney = new Money(targetAmount, new Currency(targetCurrency));
        //根据userid查找当前账户
        /**
         *  repository在这里的作用，为什么不直接调用dao层
         *  如果要增加缓存操作，代码中所有调用过dao层的代码都需要增加缓存操作，如果有一个地方忘记了，就会出现问题，缓存数据库不一致等问题
         *  通过增加repository层，可以统一增加缓存操作，减少出错的几率
         */

        Account sourceAccount = accountRepository.find(new UserId(sourceUserId));
        //根据账户号查找目标账户
        Account targetAccount = accountRepository.find(new AccountNumber(targetAccountNumber));

        ExchangeRate exchangeRate = exchangeRateService.getExchangeRate(sourceAccount.getCurrency(), targetMoney.getCurrency());
        //领域层  核心业务代码执行
        accountTransferService.transfer(sourceAccount, targetAccount, targetMoney, exchangeRate);

        accountRepository.save(sourceAccount);

        accountRepository.save(targetAccount);

        // 发送审计消息
        AuditMessage message = new AuditMessage(sourceAccount, targetAccount, targetMoney);
        auditMessageProducer.send(message);

        return Result.success(true);
    }
}
